package cn.zwx.goods.svc.rpc;

import cn.zwx.base.entity.ResponseEntity;
import cn.zwx.base.exception.BizWrapException;
import cn.zwx.base.utils.PageUtil;
import cn.zwx.base.utils.ValidationUtils;
import cn.zwx.goods.svc.constans.GoodsConstans;
import cn.zwx.goods.svc.domain.bo.BuilderSkuBO;
import cn.zwx.goods.svc.domain.bo.BuilderSpuBO;
import cn.zwx.goods.svc.domain.bo.SpuBO;
import cn.zwx.goods.svc.domain.bo.SpuPageListBO;
import cn.zwx.goods.svc.domain.entity.*;
import cn.zwx.goods.svc.domain.enums.*;
import cn.zwx.goods.svc.manager.DistributedManager;
import cn.zwx.goods.svc.rpc.dto.*;
import cn.zwx.goods.svc.rpc.facade.DubboSpuService;
import cn.zwx.goods.svc.rpc.vo.*;
import cn.zwx.goods.svc.service.CategoryService;
import cn.zwx.goods.svc.service.SkuService;
import cn.zwx.goods.svc.service.SpuService;
import cn.zwx.goods.svc.utils.SpuCodeGeneratorUtil;
import cn.zwx.goods.svc.warp.ExceptionWrap;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.apidocs.annotations.ApiDoc;
import org.apache.dubbo.apidocs.annotations.ApiModule;
import org.apache.dubbo.config.annotation.DubboService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author zhangwenxue
 */
@Service
@ApiModule(value = "商品相关接口", apiInterface = DubboSpuService.class)
@DubboService(version = "v1.0.0",interfaceClass = DubboSpuService.class,timeout = 8000)
public class DubboSpuServiceImpl implements DubboSpuService {

    public static final Logger logger = LoggerFactory.getLogger(DubboSpuServiceImpl.class);
    @Resource
    private SpuService spuService;
    @Resource
    private SkuService skuService;
    @Resource
    private CategoryService categoryService;
    @Resource
    private DistributedManager distributedManager;
    @Resource
    private SpuCodeGeneratorUtil spuCodeGeneratorUtil;

    @Override
    @ApiDoc(value = "分页查询商品列表接口")
    public ResponseEntity<PageUtil<SpuPageListVO>> pageList(SpuPageListDTO dto) throws BizWrapException {
        // 1.验证参数
        ValidationUtils.getInstance().validate(dto);
        // 2.select count
        final SpuPageListBO spuPageListBO = this.selectPageCount(dto);
        if (spuPageListBO.getReturnFlag()) {
            return ResponseEntity.success(spuPageListBO.getReturnPage());
        }
        // 3.查询数据
        Integer startIndex = dto.getPageNum().equals(GoodsConstans.INT_1)?GoodsConstans.INT_0:
                Math.subtractExact(dto.getPageNum(),1) * dto.getPageSize();
        final SpuBO spuBO = new SpuBO();
        BeanUtils.copyProperties(dto,spuBO);
        spuBO.setStartIndex(startIndex);
        List<SpuEntity> spuList = spuService.selectList(spuBO);
        // 4.返回参数处理
        final PageUtil<SpuPageListVO> returnPage = spuPageListBO.getReturnPage();
        if (CollectionUtils.isEmpty(spuList)){
            return ResponseEntity.success(returnPage);
        }
        final List<SpuPageListVO> pageList = new ArrayList<>();
        for (SpuEntity spuEntity : spuList) {
            final SpuPageListVO spuPageListVO = new SpuPageListVO();
            BeanUtils.copyProperties(spuEntity,spuPageListVO);
            pageList.add(spuPageListVO);
        }
        returnPage.setRecords(pageList);
        return ResponseEntity.success(returnPage);
    }

    private SpuPageListBO selectPageCount(SpuPageListDTO dto) {
        PageUtil<SpuPageListVO> returnPage = new PageUtil<>(dto.getPageNum(), dto.getPageSize(), GoodsConstans.INT_0,new ArrayList<>());
        LambdaQueryWrapper<SpuEntity> querySpuWrapper = new LambdaQueryWrapper<>();
        querySpuWrapper.like(StringUtils.isNotBlank(dto.getSpuName()),SpuEntity::getName, dto.getSpuName());
        querySpuWrapper.eq(StringUtils.isNotBlank(dto.getSpuCode()),SpuEntity::getSpuCode, dto.getSpuCode());
        querySpuWrapper.gt(StringUtils.isNotBlank(dto.getStartTime()),SpuEntity::getCreateTime, dto.getStartTime());
        querySpuWrapper.lt(StringUtils.isNotBlank(dto.getEndTime()),SpuEntity::getCreateTime, dto.getEndTime());
        querySpuWrapper.eq(StringUtils.isNotBlank(dto.getSpuCode()),SpuEntity::getSpuCode, dto.getSpuCode());
        querySpuWrapper.eq(!ObjectUtils.isEmpty(dto.getNewStatus()),SpuEntity::getNewStatus, dto.getNewStatus());
        querySpuWrapper.eq(!ObjectUtils.isEmpty(dto.getRecommendStatus()),SpuEntity::getRecommendStatus, dto.getRecommendStatus());
        querySpuWrapper.eq(!ObjectUtils.isEmpty(dto.getBrandId()),SpuEntity::getBrandId, dto.getBrandId());
        querySpuWrapper.eq(!ObjectUtils.isEmpty(dto.getCategoryId()),SpuEntity::getCategoryId, dto.getCategoryId());
        querySpuWrapper.eq(!ObjectUtils.isEmpty(dto.getStatus()),SpuEntity::getStatus, dto.getStatus());
        querySpuWrapper.orderByDesc(SpuEntity::getSeq);
        querySpuWrapper.orderByDesc(SpuEntity::getUpdateTime);
        querySpuWrapper.orderByDesc(SpuEntity::getCreateTime);
        Integer selectCount = spuService.selectCount(querySpuWrapper);
        if (selectCount.equals(GoodsConstans.INT_0)){
            logger.info("not select record,params:{}", JSON.toJSONString(dto));
            return new SpuPageListBO(Boolean.TRUE,returnPage);
        }
        // 重新计算分页信息
        returnPage = new PageUtil<>(dto.getPageNum(), dto.getPageSize(), selectCount,new ArrayList<>());
        return new SpuPageListBO(Boolean.FALSE,returnPage);
    }

    @Override
    @ApiDoc(value = "查询商品详情接口")
    public ResponseEntity<SpuInfoVO> info(SpuInfoDTO dto) throws BizWrapException {
        // 1.验证参数
        ValidationUtils.getInstance().validate(dto);
        // 2.查询spuId信息
        SpuEntity spuEntity = spuService.selectById(dto.getSpuId());
        if (ObjectUtils.isEmpty(spuEntity)){
            throw ExceptionWrap.wrap(GoodsCodeEnum.SPU_NOT_EXIST_ERROR);
        }
        // 3.查询属性信息
        List<SpuAttrValueEntity> valueEntityList = spuService.selectAttrBySpuId(dto.getSpuId());
        // 4.查询sku信息
        List<SkuEntity> skuList = skuService.selectBySpuId(dto.getSpuId());
        // 5.返回参数封装
        final SpuInfoVO spuInfoVO = this.packageInfoResp(spuEntity, valueEntityList, skuList);
        // 6.返回参数
        return ResponseEntity.success(spuInfoVO);
    }

    private SpuInfoVO packageInfoResp(SpuEntity spuEntity, List<SpuAttrValueEntity> valueEntityList, List<SkuEntity> skuList) {
        final SpuInfoVO spuInfoVO = new SpuInfoVO();
        spuInfoVO.setId(spuEntity.getId());
        spuInfoVO.setName(spuEntity.getName());
        spuInfoVO.setSpuCode(spuEntity.getSpuCode());
        spuInfoVO.setNewStatus(spuEntity.getNewStatus());
        spuInfoVO.setRecommendStatus(spuEntity.getRecommendStatus());
        spuInfoVO.setMainImgUrl(spuEntity.getMainImgUrl());
        spuInfoVO.setImages(spuEntity.getImages());
        spuInfoVO.setIntro(spuEntity.getIntro());
        spuInfoVO.setCategoryId(spuEntity.getCategoryId());
        spuInfoVO.setCategoryName(spuEntity.getCategoryName());
        spuInfoVO.setCategoryPId(spuEntity.getCategoryPId());
        spuInfoVO.setCategoryPName(spuEntity.getCategoryPName());
        spuInfoVO.setIsMarketable(spuEntity.getIsMarketable());
        spuInfoVO.setStatus(spuEntity.getStatus());
        spuInfoVO.setSeq(spuEntity.getSeq());
        spuInfoVO.setCategoryTopId(spuEntity.getCategoryTopId());
        spuInfoVO.setCategoryTopName(spuEntity.getCategoryTopName());
        spuInfoVO.setCreateTime(new Date());
        spuInfoVO.setUpdateTime(new Date());
        List<GoodsAttrVO> goodsAttrList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(valueEntityList)){
            valueEntityList.forEach(t->{
                final GoodsAttrVO goodsAttrVO = new GoodsAttrVO();
                goodsAttrVO.setAttrValueName(t.getAttrValueName());
                goodsAttrVO.setSpuAttrValueId(t.getSpuAttrValueId());
                goodsAttrVO.setAttrId(t.getAttrId());
                goodsAttrVO.setAttrName(t.getAttrName());
                goodsAttrList.add(goodsAttrVO);
            });
        }
        spuInfoVO.setGoodsAttrList(goodsAttrList);
        List<SkuListVO> skuInfoList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(skuList)){
            skuList.forEach(t->{
                final SkuListVO skuListVO = new SkuListVO();
                BeanUtils.copyProperties(t,skuListVO);
                skuInfoList.add(skuListVO);
            });
        }
        spuInfoVO.setSkuInfoList(skuInfoList);
        return spuInfoVO;
    }

    @Override
    @ApiDoc(value = "根据商品规格生成sku列表")
    public ResponseEntity<List<GenerateSkuListVO>> generateSkuList(GenerateSkuListDTO dto) throws BizWrapException {
        // 1.验证参数
        ValidationUtils.getInstance().validate(dto);
        // 2.构建属性映射关系
        final List<BuilderAttrDTO> attrSpuList = dto.getAttrSpuList();
        final Map<Long, List<BuilderAttrDTO>> attrMap = attrSpuList.stream().collect(Collectors.groupingBy(BuilderAttrDTO::getAttrId));
        // 3.构建属性列表
        List<BuilderAttrDTO[]> attributeList = new ArrayList<>();
        for (List<BuilderAttrDTO> attributeValues : attrMap.values()) {
            attributeList.add(attributeValues.toArray(new BuilderAttrDTO[0]));
        }
        // 4.生成SKU列表
        List<List<BuilderAttrDTO>> skuList = generateSku(attributeList, 0, new ArrayList<>());
        // 5.输出SKU列表
        final String spuName = dto.getSpuName();
        List<GenerateSkuListVO> returnList = new ArrayList<>();
        for (List<BuilderAttrDTO> attrSkuList : skuList) {

            final GenerateSkuListVO generateSkuListVO = new GenerateSkuListVO();
            List<GenerateAttrVO> attrVOList = new ArrayList<>();
            StringBuilder skuName = new StringBuilder(spuName);
            for (BuilderAttrDTO sku : attrSkuList) {
                final GenerateAttrVO generateAttrVO = new GenerateAttrVO();
                generateAttrVO.setAttrName(sku.getAttrName());
                generateAttrVO.setAttrId(sku.getAttrId());
                generateAttrVO.setAttrValueId(sku.getAttrValueId());
                generateAttrVO.setAttrValueName(sku.getAttrValueName());
                attrVOList.add(generateAttrVO);
                skuName.append(GoodsConstans.SEPARATOR_1).append(sku.getAttrValueName());
            }
            generateSkuListVO.setAttrVOList(attrVOList);
            generateSkuListVO.setSkuName(skuName.toString());
            generateSkuListVO.setSkuId(distributedManager.getDistributedId());
            returnList.add(generateSkuListVO);
        }
        // 5.返回参数
        return ResponseEntity.success(returnList);
    }

    private static List<List<BuilderAttrDTO>> generateSku(List<BuilderAttrDTO[]> attributes, int index, List<BuilderAttrDTO> current) {
        List<List<BuilderAttrDTO>> result = new ArrayList<>();
        if (index == attributes.size()) {
            result.add(new ArrayList<>(current));
            return result;
        }

        BuilderAttrDTO[] attribute = attributes.get(index);
        for (BuilderAttrDTO value : attribute) {
            current.add(value);
            result.addAll(generateSku(attributes, index + 1, current));
            current.remove(current.size() - 1);
        }

        return result;
    }

    @Override
    @ApiDoc(value = "新增商品信息接口")
    @Transactional(rollbackFor = Exception.class)
    public ResponseEntity<InsertSpuVO> insert(InsertSpuDTO dto) throws BizWrapException {
        // 1.验证请求参数
        ValidationUtils.getInstance().validate(dto);
        // 2.验证商品是否被添加过
        LambdaQueryWrapper<SpuEntity> spuWrapper = new LambdaQueryWrapper<>();
        spuWrapper.eq(SpuEntity::getName,dto.getSpu().getName());
        Integer selectCount = spuService.selectCount(spuWrapper);
        if (selectCount.compareTo(GoodsConstans.INT_0) >0){
            logger.error("新增商品信息已经存在,请求参数：{}", JSON.toJSONString(dto));
            throw  ExceptionWrap.wrap(GoodsCodeEnum.SPU_NOT_EXIST_ERROR);
        }
        // 3.构建spu信息
        final BuilderSpuBO builderSpuBO = this.builderSpuEntity(dto);
        final SpuEntity spuEntity = builderSpuBO.getSpuEntity();
        // 4.构建sku信息
        final BuilderSkuBO builderSkuBO = this.builderSkuEntity(dto.getSkuList(), spuEntity.getId());
        // 5.保存db
        spuService.insert(spuEntity);
        spuService.batchInsertAttr(builderSpuBO.getSpuAttrValueList());
        skuService.batchInert(builderSkuBO.getSkuEntityList());
        skuService.batchInsertAttr(builderSkuBO.getSkuAttrValueList());
        // 6.返回参数
        final InsertSpuVO insertSpuVO = new InsertSpuVO();
        insertSpuVO.setSpuId(spuEntity.getId());
        insertSpuVO.setSpuCode(spuEntity.getSpuCode());
        return ResponseEntity.success();
    }

    @Override
    @ApiDoc("修改商品接口")
    @Transactional(rollbackFor = Exception.class)
    public ResponseEntity<Void> modify(ModifySpuDTO dto) throws BizWrapException {
        // 1.验证参数
        ValidationUtils.getInstance().validate(dto);
        // 2.是否存在
        LambdaQueryWrapper<SpuEntity> spuWrapper = new LambdaQueryWrapper<>();
        spuWrapper.eq(SpuEntity::getId,dto.getId());
        final Integer selectCount = spuService.selectCount(spuWrapper);
        if (selectCount.compareTo(GoodsConstans.INT_0) <= 0){
            throw ExceptionWrap.wrap(GoodsCodeEnum.SPU_NOT_EXIST_ERROR);
        }
        // 3.修改信息
        final SpuEntity spuEntity = new SpuEntity();
        BeanUtils.copyProperties(dto,spuEntity);
        spuEntity.setUpdateTime(new Date());
        spuService.update(spuEntity);
        // 4.更新属性信息
        spuService.deleteAttrBySpuId(dto.getId());
        final List<SpuAttrValueEntity> spuAttrList = builderSpuAttrValueList(dto.getAttrSpuList(), spuEntity.getId());
        spuService.batchInsertAttr(spuAttrList);
        // 5.更新sku信息
        final List<BuilderSkuDTO> skuList = dto.getSkuList();
        final List<String> skuIdList = skuList.stream().map(BuilderSkuDTO::getSkuId).collect(Collectors.toList());
        skuService.deleteBySkuId(skuIdList);
        final BuilderSkuBO builderSkuBO = this.builderSkuEntity(skuList, spuEntity.getId());
        skuService.batchInert(builderSkuBO.getSkuEntityList());
        skuService.batchInsertAttr(builderSkuBO.getSkuAttrValueList());
        // 6.返回参数
        return ResponseEntity.success();
    }

    @Override
    @ApiDoc("删除商品接口")
    @Transactional(rollbackFor = Exception.class)
    public ResponseEntity<Void> delete(DeleteSpuDTO dto) throws BizWrapException {
        // 1.验证参数
        ValidationUtils.getInstance().validate(dto);
        // 2.删除spu信息
        spuService.deleteSpuById(dto.getSpuId());
        // 3.删除sku信息
        skuService.deleteSkuBySpuId(dto.getSpuId());
        // 4.返回参数
        return ResponseEntity.success();
    }

    private BuilderSkuBO builderSkuEntity(List<BuilderSkuDTO> skuList , String spuId) throws BizWrapException {
        final List<SkuEntity> skuEntityList = new ArrayList<>();
        final List<SkuAttrValueEntity> skuAttrValueList = new ArrayList<>();
        for (BuilderSkuDTO builderSkuDTO : skuList) {
            final SkuEntity skuEntity = new SkuEntity();
            skuEntity.setId(distributedManager.getDistributedId());
            skuEntity.setSpuId(spuId);
            skuEntity.setName(builderSkuDTO.getName());
            skuEntity.setMarketPrice(builderSkuDTO.getMarketPrice());
            skuEntity.setPrice(builderSkuDTO.getPrice());
            skuEntity.setPreWarningNum(builderSkuDTO.getPreWarningNum());
            skuEntity.setNum(builderSkuDTO.getNum());
            skuEntity.setImage(builderSkuDTO.getImage());
            skuEntity.setImages(builderSkuDTO.getImages());
            skuEntity.setStatus(SkuStatusEnum.NORMAL.getCode());
            skuEntity.setModelId(builderSkuDTO.getModelId());
            skuEntity.setWeight(new BigDecimal(builderSkuDTO.getWeight().toString()));
            skuEntity.setVolume(new BigDecimal(builderSkuDTO.getVolume().toString()));
            skuEntity.setSort(builderSkuDTO.getSort());
            skuEntity.setCreateTime(new Date());
            skuEntity.setUpdateTime(new Date());
            final SkuAttrValueEntity valueEntity = new SkuAttrValueEntity();
            final List<BuilderAttrDTO> attrSkuList = builderSkuDTO.getAttrSkuList();
            for (BuilderAttrDTO attrSku : attrSkuList) {
                valueEntity.setSpuId(spuId);
                valueEntity.setSkuId(skuEntity.getId());
                valueEntity.setAttrId(attrSku.getAttrId().intValue());
                valueEntity.setAttrName(attrSku.getAttrName());
                valueEntity.setAttrValueId(attrSku.getAttrValueId().intValue());
                valueEntity.setAttrValueName(attrSku.getAttrValueName());
                valueEntity.setCreateTime(new Date());
                valueEntity.setUpdateTime(new Date());
                skuAttrValueList.add(valueEntity);
            }
            skuEntityList.add(skuEntity);
        }
        return new BuilderSkuBO(skuEntityList,skuAttrValueList);
    }

    private BuilderSpuBO builderSpuEntity(InsertSpuDTO dto) throws BizWrapException {
        final BuilderSpuDTO spuBuilder = dto.getSpu();
        final List<Integer> categoryIdList = Arrays.asList(spuBuilder.getCategoryId(), spuBuilder.getCategoryPId(), spuBuilder.getCategoryTopId());
        List<CategoryEntity> categoryList = categoryService.selectByIdList(categoryIdList);
        if (CollectionUtils.isEmpty(categoryList) || categoryList.size() != categoryIdList.size() ){
            logger.error("未查询到商品类目信息,请求参数：{},返回参数：{}", JSON.toJSONString(categoryIdList),JSON.toJSONString(categoryIdList));
            throw  ExceptionWrap.wrap(GoodsCodeEnum.CATEGORY_INFO_NOT_EXIST_ERROR);
        }
        // 3.2 构建spu entity
        final Map<Integer, CategoryEntity> categoryEntityMap = categoryList.stream().collect(Collectors.toMap(CategoryEntity::getId,
                Function.identity(), (key1, key2) -> key2));
        final SpuEntity spuEntity = new SpuEntity();
        spuEntity.setId(distributedManager.getDistributedId());
        spuEntity.setBrandId(spuBuilder.getBrandId());
        spuEntity.setCategoryId(spuBuilder.getCategoryId());
        spuEntity.setCategoryName(categoryEntityMap.get(spuBuilder.getCategoryId()).getName());
        spuEntity.setCategoryPId(spuBuilder.getCategoryPId());
        spuEntity.setCategoryPName(categoryEntityMap.get(spuBuilder.getCategoryPId()).getName());
        spuEntity.setCategoryTopId(spuBuilder.getCategoryTopId());
        final LocalDate localDate = LocalDate.now();
        final String spuCode = spuCodeGeneratorUtil.generateProductCode(spuBuilder.getCategoryId().toString(),
                GoodsConstans.INT_1.toString(), localDate);
        spuEntity.setSpuCode(spuCode);
        spuEntity.setNewStatus(spuBuilder.getNewStatus());
        spuEntity.setRecommendStatus(spuBuilder.getRecommendStatus());
        spuEntity.setMainImgUrl(spuBuilder.getMainImgUrl());
        spuEntity.setImages(spuBuilder.getImages());
        spuEntity.setIntro(spuBuilder.getIntro());
        spuEntity.setBrandId(spuBuilder.getBrandId());
        spuEntity.setIsMarketable(MarketableEnum.UN_LISTING.getCode());
        spuEntity.setIsDelete(DelFlag.normal.getCode());
        spuEntity.setStatus(GoodsStatusEnum.WAIT.getCode());
        spuEntity.setSeq(spuBuilder.getSeq());
        spuEntity.setCreateTime(new Date());
        spuEntity.setUpdateTime(new Date());
        final List<SpuAttrValueEntity> spuAttrList = builderSpuAttrValueList(dto.getAttrSpuList(), spuEntity.getId());

        return new BuilderSpuBO(spuEntity,spuAttrList);
    }

    private static List<SpuAttrValueEntity> builderSpuAttrValueList(List<BuilderAttrDTO> attrSpuList , String spuId) {
        final List<SpuAttrValueEntity> spuAttrList = new ArrayList<>();
        attrSpuList.forEach(t->{
            final SpuAttrValueEntity valueEntity = new SpuAttrValueEntity();
            valueEntity.setSpuId(spuId);
            valueEntity.setAttrValueId(t.getAttrValueId());
            valueEntity.setAttrValueName(t.getAttrValueName());
            valueEntity.setAttrId(t.getAttrId());
            valueEntity.setAttrName(t.getAttrName());
            spuAttrList.add(valueEntity);
        });
        return spuAttrList;
    }
}
